/*****************************************************************************
* Copyright (C) 2016 xIVC project, Peking University Shenzhen Graduate School
*
* Authors: Ronggang Wang <rgwang@pkusz.edu.cn>
*		   Zhenyu Wang <wangzhenyu@pkusz.edu.cn>
*          Kui Fan <kuifan@pku.edu.cn>
*		   Shenghao Zhang <1219759986@qq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at rgwang@pkusz.edu.cn.
*****************************************************************************/

#ifndef __COMMON_H__
#define __COMMON_H__

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include <memory.h>
#include "defines.h"
#include "global.h"

#define DEBUG_TEST 0

#if DEBUG_TEST
extern FILE* g_debug_fp;
#endif

/* ---------------------------------------------------------------------------
 * log level
 */
#define COM_LOG_NONE       (-1)
#define COM_LOG_ERROR      0
#define COM_LOG_WARNING    1
#define COM_LOG_INFO       2
#define COM_LOG_DEBUG      3

/* ---------------------------------------------------------------------------
 * date align
 */
#if defined(_WIN32)
#define DECLARE_ALIGNED(var, n) __declspec(align(n)) var
#else
#define DECLARE_ALIGNED(var, n) var __attribute__((aligned (n))) 
#endif
#define ALIGNED_32(var)    DECLARE_ALIGNED(var, 32)
#define ALIGNED_16(var)    DECLARE_ALIGNED(var, 16)
#define ALIGNED_8(var)    DECLARE_ALIGNED(var, 8)
#define ALIGNED_4(var)    DECLARE_ALIGNED(var, 4)

#define ALIGN_BASIC 32 // for new generation CPU with 256-bits SIMD
#define ALIGN_MASK (ALIGN_BASIC - 1)
#define ALIGN_POINTER(x) (x + ALIGN_MASK - (((intptr_t)x + ALIGN_MASK) & ((intptr_t)ALIGN_MASK)))

/* ---------------------------------------------------------------------------
 * basic math operations
 */
#define COM_ABS(a)         ((a) < (0) ? (-(a)) : (a))
#define COM_MAX(a, b)      ((a) > (b) ? (a) : (b))
#define COM_MIN(a, b)      ((a) < (b) ? (a) : (b))
#define COM_CLIP3( min, max, val) (((val)<(min))? (min):(((val)>(max))? (max):(val)))
#define COM_ADD_MODE(v, mode) ((v) & (mode - 1))

/* ---------------------------------------------------------------------------
 * memory opterations
 */
typedef union {
    i16u_t    i;
    uchar_t   c[2];
} com_union16_t;

typedef union {
    i32u_t    i;
    i16u_t    b[2];
    uchar_t   c[4];
} com_union32_t;

typedef union {
    i64u_t    i;
    i32u_t    a[2];
    i16u_t    b[4];
    uchar_t   c[8];
} com_union64_t;

#define M16(src)                (((com_union16_t*)(src))->i)
#define M32(src)                (((com_union32_t*)(src))->i)
#define M64(src)                (((com_union64_t*)(src))->i)

#define CP16(dst,src)           M16(dst) = M16(src)
#define CP32(dst,src)           M32(dst) = M32(src)
#define CP64(dst,src)           M64(dst) = M64(src)

/* ---------------------------------------------------------------------------
 * simd/neon/.... declare
 */
#define SIMD_NAME(func) func##_sse128

/* ---------------------------------------------------------------------------
 * memory alloc & free
 */
void *com_malloc(int i_size);
void  com_free(void *p);

/* ---------------------------------------------------------------------------
 * functions handle
 */
enum IPFilterConf {
    IPFILTER_H_4,
	IPFILTER_H_6,
	IPFILTER_H_10,
	IPFILTER_V_4,
    IPFILTER_V_6,
    IPFILTER_V_10,
    NUM_IPFILTER
};

enum IPFilterConf_Ext {
    IPFILTER_EXT_4,
    IPFILTER_EXT_6,
	IPFILTER_EXT_10,
	NUM_IPFILTER_Ext
};


typedef struct {
//	// inter filter
//    void(*ipcpy) (const pel_t *src, int i_src, pel_t *dst, int i_dst, int width, int height);
 //   void(*ipflt[NUM_IPFILTER]) (const pel_t *src, int i_src, pel_t *dst, int i_dst, int width, int height, const char_t *coeff, int max_val);
	//void(*ipflt_EXT[NUM_IPFILTER_Ext]) (const pel_t *src, int i_src, pel_t *dst, int i_dst, int width, int height, const char_t *coeff_h, const char_t *coeff_v, int max_val);
	//void(*ipflt_chroma_subpix_EXT[NUM_IPFILTER_Ext]) (const pel_t *src, int i_src, pel_t *dst, int i_dst, const char_t *coeff_h, const char_t *coeff_v);
//    
//
//    void(*cpy) (const pel_t *src, int i_src, pel_t *dst, int i_dst, int width, int height);
//    void(*cpy_pel_to_uchar)(const pel_t *src, int i_src, uchar_t *dst, int i_dst, int width, int height, int bit_size);
//    void(*cpy_pel_I420_to_uchar_YUY2)(const pel_t *srcy, const pel_t *srcu, const pel_t *srcv, int i_src, int i_srcc, uchar_t *dst, int i_dst, int width, int height, int bit_size);
//	
//    void(*padding_rows_lr)(pel_t *src, int i_src, int width, int height, int start, int rows, int pad);
//	
//
//    
//
//    //void(*idct_sqt[5])(coef_t *blk, int shift, int clip);
//    void(*idct_hor[3])(coef_t *blk, int shift, int clip);
//    void(*idct_ver[3])(coef_t *blk, int shift, int clip);
//    void(*inv_2nd_hor)(coef_t *blk, int i_blk, int shift, const i16s_t coef[4][4]);
//    void(*inv_2nd_ver)(coef_t *blk, int i_blk, int shift, const i16s_t coef[4][4]);
//    void(*inv_2nd)(coef_t *blk, int i_blk, int shift, int clip_depth, const i16s_t coef[4][4]);
//    void(*inv_wavelet)(coef_t *blk);
//    void(*inv_wavelet_hor)(coef_t *blk);
//    void(*inv_wavelet_ver)(coef_t *blk);
//
//    void(*alf_flt)(pel_t *imgRes, pel_t *imgPad, int stride, int isChroma, int yPos, int lcu_height, int xPos, int lcu_width, int *coef, int sample_bit_depth, int isAboveAvail, int isBelowAvail);
//
//
	// deb-lock
	void(*deblock_edge[2])(uchar_t* SrcPtr, int istride, bool bChroma, int edge);


	// intra filter
	void(*intra_pred_luma_dc)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight, bool bAboveAvail, bool bLeftAvail);
	void(*intra_pred_chroma_dc)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight, int, int, bool bAboveAvail, bool bLeftAvail);
	void(*intra_pred_ver)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight);
	void(*intra_pred_hor)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight);
	void(*intra_pred_downright)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight);
	void(*intra_pred_downleft)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight);
	void(*intra_pred_chroma_plane)(unsigned char *pSrc, pel_t *pDst, int i_dst, int iBlkWidth, int iBlkHeight, int x_off, int y_off);

	// dct
	void(*dct_sqt[2])(int *curr_blk);
	void(*dct_sqt_16)(int *curr_blk, int bsize);

	// idct
	void(*idct_sqt[2])(int *curr_blk);
	void(*idct_sqt_16)(int *curr_blk, int bsize);

	// pixel 
	void(*add_pel_clip)(int b8, int b4, int* curr_blk, int bsize, \
						int (*ppredblk)[16], int(*pm7)[16], int ipix_y, \
						int iStride, int ipix_x, int ipix_c_y, int ipix_c_x, int iStrideC);
	void(*padding_rows)(pel_t *src, int i_src, int width, int height, int pad);

	void(*post_rdoquant)(const int bsize, const int *src, int *dst);
	void(*quant_B8)( int qp, int mode, int *curr_blk, int bsize, int Q);
	void(*inv_quant)(int coef_num, int qp, int bsize, const int *IVC_SCAN, int *curr_blk, int shift, int QPI);
//#ifdef MT_ENABLE
//	void(*padding_rows_LR_mt)(pel_t *src, int i_src, int width, int height, int pad, int mb_row, bool uv_flag);
//#endif // MT_ENABLE
//
//	void(*avg_pel)(pel_t *dst, int i_dst, pel_t *src1, int i_src1, pel_t *src2, int i_src2, int width, int height);
//	void(*com_cpy)(const pel_t *src, int i_src, pel_t *dst, int i_dst, int width, int height);
	
} funs_handle_t;

extern funs_handle_t g_funs_handle;

/* ---------------------------------------------------------------------------
 * function handle init for c coding
 */
void com_funs_init_intra_pred();
void com_funs_init_ip_filter();
void com_funs_init_pixel_opt();
void com_funs_init_deblock_filter();
void com_funs_init_dct();
void com_funs_init_idct();
void com_funs_init_alf_filter();

//void com_init_intrinsic_256();
void com_init_intrinsic();
//void com_init_neon128();

#endif // #ifndef __COMMON_H__